import { Queue } from "../../../Support/Share/Lib/Collections/Queue";
import { TimerCoreInvokeType } from "../../TimerCoreInvokeType";
import { ObjectPool } from "../ObjectPool/ObjectPool";
import { TimeHelper } from "../Time/TimeHelper";
import { TimerComponent } from "../Timer/TimerComponent";
import { CoroutineLock } from "./CoroutineLock";
import { WaitCoroutineLock } from "./WaitCoroutineLock";

export class CoroutineLockQueue {
    private type: number;
    private key: number;

    public static Create(type: number, key: number): CoroutineLockQueue {
        let coroutineLockQueue = ObjectPool.Instance.Fetch(CoroutineLockQueue);
        coroutineLockQueue.type = type;
        coroutineLockQueue.key = key;
        return coroutineLockQueue;
    }

    private currentCoroutineLock?: CoroutineLock;

    private queue: Queue<WaitCoroutineLock> = new Queue<WaitCoroutineLock>();

    get Count(): number {
        return this.queue.Count;
    }

    public async Wait(time: number): Promise<CoroutineLock> {
        if (!this.currentCoroutineLock) {
            this.currentCoroutineLock = CoroutineLock.Create(this.type, this.key, 1);
            return this.currentCoroutineLock;
        }

        let waitCoroutineLock = WaitCoroutineLock.Create();

        this.queue.Enqueue(waitCoroutineLock);

        if (time > 0) {
            const tillTime = TimeHelper.ClientFrameTime() + time;

            TimerComponent.Instance.NewOnceTimer(tillTime, TimerCoreInvokeType.CoroutineTimeout, waitCoroutineLock);
        }

        this.currentCoroutineLock = await waitCoroutineLock.Wait();
        return this.currentCoroutineLock;
    }

    public Notify(level: number) {
        while (this.queue.Count > 0) {
            let waitCoroutineLock = this.queue.Dequeue();

            if (waitCoroutineLock.IsDisposed())
                continue;

            const coroutineLock = CoroutineLock.Create(this.type, this.key, level);

            waitCoroutineLock.SetResult(coroutineLock);
            break;
        }
    }

    public Recycle() {
        this.queue.Clear();
        this.key = 0;
        this.type = 0;
        this.currentCoroutineLock = null;
        ObjectPool.Instance.Recycle(this);
    }

}
